Swift 入门教程 - 集合

少抱怨,多思考,未来生活很美好。

上一章讲了常量、变量、基本类型和格式化输出。这一章来讲一下 Swift 中的集合。

什么是集合呢?简而言之就是存放一堆数据的容器。

在 Swift 中,一共有三种集合类型:Array、Set、Dictionary。三种集合类型的简要定义如下:

  • Array:存放有序且类型相同的一组元素
  • Set:存放无序、值唯一且类型相同的一组元素。
  • Dictionary:存放无序,键值对形式的元素。

注意:用 let 声明的常量是不可更改的集合,用 var 声明的为可更改的集合。
Apple 官方文档 - 三种数据结构图解

下面详细介绍一些这三种类型。

数组(Array)

数组用来存放有序、类型相同的多个元素。它的索引是从 0 开始计算的,也就是说它的最后一个元素的索引等于它的总长度减一。下面我们来看一下数组的基本使用。

创建一个空数组

有以下两种方式来创建一个空数组。

  • 完整版

    1
    var intArrFull = Array<Int>()
  • 简洁版

    1
    var intArrShortcut = [Int]()

官方文档推荐使用简洁版,言简意赅。

创建有默认值的数组

1
2
3
4
// repeating:需要重复的值,count:重复的次数
var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles 的类型时 [Double] 上述代码等同于
// var threeDoubles = [0.0, 0.0, 0.0]

通过该函数我们可以快速创建带有多个重复值的数组,而无需写大量冗余代码。

数组的基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var languages = ["Swift", "Java", "Objective-C"]
// 增
languages.append("Python")
// languages: ["Swift", "Java", "Objective-C", "Python"]
languages.insert("C++", at: 1)
// ["Swift", "C++", "Java", "Objective-C", "Python"]
// 删
languages.remove(at: 2)
// ["Swift", "C++", "Objective-C", "Python"]
// 改
languages[1] = "C"
// ["Swift", "C", "Objective-C", "Python"]
// 查
let lang = languages[0]
// Swift

注意点:

  • 使用数组最重要的也是最容易犯错的地方:不要越界、不要越界、不要越界(数组越界的意思就是索引超出数组长度)。
  • let 修饰的是不可变数组;用 var 修饰的是可变数组。
  • 调用 append() 函数添加的元素放在数组的最后,调用insert()函数则是放在你指定的位置。

数组合并:

1
2
3
4
var lang1 = ["Swift", "Java", "Objective-C"]
var lang2 = ["C"]
let languages = lang1 + lang2
// ["Swift", "Java", "Objective-C", "C"]

数组的常用属性

  • count 代表数组的长度。
  • isEmpty 代表数组是否为空。
  • first 代表数组的第一个元素,它是 optional 类型,若没有则返回 nil。
  • last 代表数组的最后一个元素,它是 optional 类型,若没有则返回 nil。
1
2
3
4
5
let languages = ["Swift", "Java", "Objective-C"]
let count = languages.count // 3
let isEmpty = languages.isEmpty // false
let first = languages.first // Swift 类型为 String?
let last = languages.last // Objective-C 类型为 String?

遍历数组

1
2
3
4
5
let languages = ["Swift", "Java", "Objective-C"]
for lang in languages {
print(lang)
}
// print: Swift Java Objective-C

Set

set 是用来存储相同类型、无序且值唯一的多个元素。

什么时候使用 set:

  • 当你的数据对于顺序没有特定要求时,你可以用 set 来替代数组。
  • 当需要一个元素只能出现一次时。

使用 Set 数据结构需满足的条件

使用 Set 存储的元素必须是可哈希的,也就是说元素必须提供一种方式去计算它本身的哈希值。Set 正是通过比较每个元素的哈希值来确保每个元素只出现一次。

Swift 中的基本类型默认都是可哈希的(String、Int、Double、Bool等)。

Set 的基本使用

1
2
3
4
5
6
7
8
9
10
//创建 Set
var locations: Set = ["bj", "nj", "dj"]
// 增
locations.insert("xj")
// 删
locations.remove("nj")
// 遍历 Set
for location in locations {
print(location)
}

这里需要说明一下 Set 的删除操作,如果 Set 包含要删除的值,调用 remove 方法会删除并返回该值,反之则返回 nil

1
2
3
4
let deleteContainValue = locations.remove("dj")
let deleteUncontainValue = locations.remove("sh")
// deleteContainValue = dj deleteUncontainValue = nil
print(deleteContainValue, deleteUncontainValue)

常用属性

  • count
  • isEmpty
  • func contains(_ member: String) -> Bool
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 获取 Set 的数量
    print(locations.count)
    // 判断 Set 是否为空
    if locations.isEmpty {
    print("locations 为空")
    }
    // 判断 Set 是否包含某个值
    if locations.contains("sh") {
    print("locations 包含 sh")
    } else {
    print("locations 未包含 sh")
    }

Set 的常用操作

  • intersection(_:):用两个 set 的合集创建新的 set。
  • symmetricDifference(_:):用两个 set 的非合集创建新的 set。
  • union(_:):用两个 set 的全部值创建新的 set。
  • subtracting(_:):用当前 set 与另一个 set 的非合集创建新的 set。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 因为 set 是无序的,所以调用 sorted() 方法对结果进行排序
    let oddDigits: Set = [1, 3, 5, 7, 9]
    let evenDigits: Set = [0, 2, 4, 6, 8]
    let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
    oddDigits.union(evenDigits).sorted()
    // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    oddDigits.intersection(evenDigits).sorted()
    // []
    oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
    // [1, 9]
    oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
    // [1, 2, 9]
Apple 官网 - Set 的操作

Set 的逻辑关系操作

  • ==:判断两个 set 包含的所有值都相同。
  • isSubset(of:):判断当前 set 是另一个 set 的子集。
  • isSuperset(of:):判断是否当前 set 是另一个 set 的父集。
  • isStrictSubset(of:) / isStrictSuperset(of:):判断是否为子集或者父集,并且两个不相同。
  • isDisjoint(with:):判断是否两个 set 无交集。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let houseAnimals: Set = ["🐶", "🐱"]
let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]
let cityAnimals: Set = ["🐦", "🐭"]
houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true
let subSetEqual: Set = ["🐶", "🐱"]
let subSetNoteEqual: Set = ["🐶"]
let equal = subSetEqual.isStrictSubset(of: houseAnimals) // false
let notEqual = subSetNoteEqual.isStrictSubset(of: houseAnimals) // true
Apple 官网 - Set 的逻辑关系

字典(Dictionary)

字典用来存储键值对结构(key - value)的数据,它是无序的。它的键是唯一的,不可重复;而它的值是可以重复的。它和现实中的字典很类似。

注意:它所有的键必须是同一类型,并且因为需要保证键的唯一性,所以类型也必须遵守 Hashable 协议。

字典的基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 创建一个空的字典,类型为:[String: String]
var student = [String: String]()
// 给字典赋值
student["name"] = "xiaoming"
student["age"] = "18"
// 给同一个键赋值,会覆盖之前的旧值
student["age"] = "20"
student["weight"] = "60.5"
// ["name": "xiaoming", "age": "20", "weight": "60.5"]
print(student)
// 删除 item
student["height"] = nil
// ["weight": "60.5", "name": "xiaoming", "age": "20"]
print(student)
// 是否包含某个键
if let weight = student["weight"] {
print(weight)
} else {
print("字典不包含 weight")
}
// 60.5

常用属性

  • count
  • isEmpty
    1
    2
    print(student.count) // 3,它含有 3 个 item。一个键值对为一个 item
    print(student.isEmpty) // false

遍历字典

  • 遍历所有的键

    1
    2
    3
    4
    5
    6
    7
    8
    for key in student.keys {
    print(key)
    }
    //weight
    //age
    //name
    //height
  • 遍历所有的 item

    1
    2
    3
    4
    5
    6
    7
    for (key, value) in student {
    print(key, value)
    }
    //weight 60.5
    //name xiaoming
    //height 1.75
    //age 20

总结

这三种数据结构是日常开发中,每天都要和它们打交道,尤其是数组和字典,所以我们要将它们的概念和用法烂熟于心。

  • Array:存储相同类型的值,可重复,有序。
  • Set:存储相同类型的值,值唯一,无序。
  • Dictionary:存储键值对,键唯一,无序。

文中的部分示例代码来自于官网。